package com.jack.netty.tcp.server;

import com.jack.netty.log.LoggerManager;
import com.jack.netty.message.Ping;
import com.jack.netty.message.Pong;
import com.jack.netty.message.UserMsg;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

/**
 * Created by jack on 2015/5/21 0021.
 */
public class TLVServerHandler extends ChannelHandlerAdapter {

    private String attributeKeyPingCount = "attributeKeyPingCount";
    private final AttributeKey<Integer> pingKey = AttributeKey.valueOf(attributeKeyPingCount);

    private final String helloStr = "欢迎使用jack通讯系统!";

    private int failHeartCount = 5;

    private String clientName = "客户端";

    private TLVServerListener tlvServerListener;

    public TLVServerHandler(TLVServerListener tlvServerListener){
        this.tlvServerListener = tlvServerListener;
        if(this.tlvServerListener == null){
            LoggerManager.getInstance().getiLogger().error(getClass(),"未设置 TLVServerListener");
        }
    }

    public TLVServerHandler(TLVServerListener tlvServerListener,String clientName){
        this.tlvServerListener = tlvServerListener;
        this.clientName = clientName;
        if(this.tlvServerListener == null){
            LoggerManager.getInstance().getiLogger().error(getClass(),"未设置 TLVServerListener");
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent idleStateEvent = (IdleStateEvent)evt;
            if(idleStateEvent.state() == IdleState.READER_IDLE){
                ctx.writeAndFlush(Ping.getInstance());

                //处理ping的计数增加
                Attribute<Integer> pingAttr = ctx.attr(pingKey);
                Integer pingCount = pingAttr.get();
                if(pingCount == null){
                    pingCount = 1;
                }else{
                    if(pingCount > failHeartCount){
                        //大量心跳木有回应，判断用户离线,关闭连接
                        LoggerManager.getInstance().getiLogger().info(getClass(),"感知到"+clientName+":"+ctx.channel().id().asLongText()+"无响应");
                        ctx.close();
                    }else{
                        pingCount += 1;
                    }
                }
                LoggerManager.getInstance().getiLogger().debug(getClass(),clientName+"心跳检测,id:" + ctx.channel().id().asLongText() + ",pingCount:" + pingCount);
                pingAttr.set(pingCount);

            }else if(idleStateEvent.state() == IdleState.WRITER_IDLE){
                //
            }
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        LoggerManager.getInstance().getiLogger().info(getClass(),clientName+"连接上来了,id:" + ctx.channel().id().asLongText());
        ctx.writeAndFlush(helloStr);
        ServerSessionManager.add(ctx.channel().id().asLongText(),ctx);
        tlvServerListener.onClientConnect(ctx.channel().id().asLongText());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        LoggerManager.getInstance().getiLogger().info(getClass(),clientName+"断开连接了,id:" + ctx.channel().id().asLongText());
        ServerSessionManager.del(ctx.channel().id().asLongText());
        tlvServerListener.onClientDisconnect(ctx.channel().id().asLongText());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        //处理ping的计数递减
        Attribute<Integer> pingAttr = ctx.attr(pingKey);
        Integer pingCount = pingAttr.get();
        if(pingCount == null){
            pingCount = new Integer(0);
        }else{
            pingCount = 0;
        }
        pingAttr.set(pingCount);

         //处理消息
        if(msg instanceof Ping){
            LoggerManager.getInstance().getiLogger().debug(getClass(),"收到"+clientName+":" + ctx.channel().id().asLongText() + " ping");
            //回应ping
            ctx.writeAndFlush(Pong.getInstance());

        }else if(msg instanceof Pong){
            LoggerManager.getInstance().getiLogger().debug(getClass(),"收到"+clientName+":" + ctx.channel().id().asLongText() + " pong");

        }else if(msg instanceof UserMsg){

            //处理消息
            UserMsg userMsg = (UserMsg)msg;
            String msgStr = new String(userMsg.getData(),"utf8");
            LoggerManager.getInstance().getiLogger().info(getClass(),"收到"+clientName+":" + ctx.channel().id().asLongText() + " 的消息:" + msgStr);

            try {
                tlvServerListener.onClientMessage(ctx.channel().id().asLongText(),msgStr);
            }catch (Exception e){
                LoggerManager.getInstance().getiLogger().error(getClass(),"处理"+clientName+"消息错误:"+e.getMessage());
            }
        }else{
            LoggerManager.getInstance().getiLogger().info(getClass(),"收到"+clientName+":"+ctx.channel().id().asLongText()+" 的消息:"+msg.toString());
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LoggerManager.getInstance().getiLogger().error(getClass(),clientName+":" + ctx.channel().id().asLongText() + " 错误:" + cause.getMessage());
        ctx.close();
    }

    public String getClientName() {
        return clientName;
    }

    public void setClientName(String clientName) {
        this.clientName = clientName;
    }
}
